<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8" />

    

    

    <title>springboot全局异常处理和入参格式校验 | 郑礼德技术栈</title>
    <meta name="author" content="郑礼德" />
    <meta name="keywords" content="" />
    <meta name="description" content="处理springboot出入参校验异常，全局异常等其他异常统一返回信息。使用注解@RestControllerAdvice 是组件注解，他使得其实现类能够被classpath扫描自动发现，如果应用是通过MVC命令空间或MVC Java编程方式配置，那么该特性默认是自动开启的@ExceptionHandler 用于处理统一异常情况定义全局异常处理类/*** * * Author zhenglide * 全局异常处理器 * */@RestControllerAdvice..." />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />

    
    <link rel="alternate" href="/homepage/atom.xml" title="郑礼德技术栈" type="application/atom+xml">
    
    
    <link rel="icon" href="/homepage/images/favicon.ico">
    

    <style type="text/css">
    @font-face {
        font-family: 'icomoon';
        src: url("/homepage/fonts/icomoon.eot?q628ml");
        src: url("/homepage/fonts/icomoon.eot?q628ml#iefix") format('embedded-opentype'),
             url("/homepage/fonts/icomoon.ttf?q628ml") format('truetype'),
             url("/homepage/fonts/icomoon.woff?q628ml") format('woff'),
             url("/homepage/fonts/icomoon.svg?q628ml#icomoon") format('svg');
        font-weight: normal;
        font-style: normal;
    }
    </style>
    
<link rel="stylesheet" href="/homepage/css/style.css">


    <!--[if lt IE 9]>
    <style type="text/css">
    .nav-inner {top:0;}
    .author-meta {position:static;top:0;}
    .search-form {height:36px;}
    </style>
    <script type="text/javascript" src="https://unpkg.com/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
    <![endif]-->
<meta name="generator" content="Hexo 4.2.0"></head>
<body>

    <main class="app">
        <header id="header" class="header clearfix">
    <div id="nav" class="nav">
    <div class="nav-mobile">
        <button id="open-panel" class="open-panel nav-mobile-item"><i class="icon-documents"></i></button>
        <h1 class="nav-mobile-title nav-mobile-item">郑礼德技术栈</h1>
        <button id="open-menus" class="open-panel nav-mobile-item"><i class="icon-library"></i></button>
    </div>

    <nav id="nav-inner" class="nav-inner">
        
            <a class="nav-item" href="/homepage/">
                <span class="nav-text">首页</span>
            </a>
        
            <a class="nav-item" href="/homepage/categories/front-end">
                <span class="nav-text">前端</span>
            </a>
        
            <a class="nav-item" href="/homepage/categories/back-end">
                <span class="nav-text">后端</span>
            </a>
        
            <a class="nav-item" href="/homepage/categories/linux">
                <span class="nav-text">linux部署</span>
            </a>
        
            <a class="nav-item" href="/homepage/tags">
                <span class="nav-text">标签</span>
            </a>
        
            <a class="nav-item" href="/homepage/archives">
                <span class="nav-text">归档</span>
            </a>
        
            <a class="nav-item" href="/homepage/about">
                <span class="nav-text">关于</span>
            </a>
        
    </nav>
</div>

    <aside id="aside" class="aside">
    <div id="aside-mask" class="aside-mask"></div>
    <div id="aside-inner" class="aside-inner">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit"><i class="icon-search-stroke"></i></button><input type="hidden" name="sitesearch" value="http://zhenglide.gitee.io/homepage"></form>

        
        
        
        

        
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#使用注解"><span class="toc-number">1.</span> <span class="toc-text">使用注解</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#定义全局异常处理类"><span class="toc-number">2.</span> <span class="toc-text">定义全局异常处理类</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#统一返回处理"><span class="toc-number">3.</span> <span class="toc-text">统一返回处理</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#body添加校验"><span class="toc-number">4.</span> <span class="toc-text">body添加校验</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#params添加校验"><span class="toc-number">5.</span> <span class="toc-text">params添加校验</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#添加自定义异常类"><span class="toc-number">6.</span> <span class="toc-text">添加自定义异常类</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#添加注解类"><span class="toc-number">6.1.</span> <span class="toc-text">添加注解类</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#添加异常校验类"><span class="toc-number">6.2.</span> <span class="toc-text">添加异常校验类</span></a></li></ol></li></ol>
        
    </div>
</aside>

</header>

        <div id="content" class="content">
            <div id="wrapper" class="wrapper" style="max-width: 800px">
                <article class="article" itemscope itemprop="blogPost">
    
    <header class="article-header">
        
        <h1 itemprop="name">
            springboot全局异常处理和入参格式校验
        </h1>
        
        <div class="article-meta clearfix">
            <a class="article-date" href="http://zhenglide.gitee.io/homepage/2020/03/30/springboot%E5%85%A8%E5%B1%80%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E5%92%8C%E5%85%A5%E5%8F%82%E6%A0%BC%E5%BC%8F%E6%A0%A1%E9%AA%8C/index.html">
    
    <i class="icon-calendar"></i>
    
    <time datetime="2020-03-30T09:32:26.000Z" itemprop="datePublished">2020-03-30</time>
</a>

            
<div class="article-tag-list">
    <i class="icon-tag"></i>
    <a class="article-tag-link" href="/homepage/tags/springboot/" rel="tag">springboot</a>
</div>


        </div>
    </header>
    
    <section class="article-body markdown-body">
        
        <p>处理springboot出入参校验异常，全局异常等其他异常统一返回信息。</p>
<a id="more"></a>

<h2 id="使用注解"><a href="#使用注解" class="headerlink" title="使用注解"></a>使用注解</h2><p>@RestControllerAdvice 是组件注解，他使得其实现类能够被classpath扫描自动发现，如果应用是通过MVC命令空间或MVC Java编程方式配置，那么该特性默认是自动开启的</p>
<p>@ExceptionHandler 用于处理统一异常情况</p>
<h2 id="定义全局异常处理类"><a href="#定义全局异常处理类" class="headerlink" title="定义全局异常处理类"></a>定义全局异常处理类</h2><pre><code class="java">/***
 *
 * Author zhenglide
 * 全局异常处理器
 *
 */
@RestControllerAdvice
public class GloablExceptionHandler {
     public final   static  Logger log = LoggerFactory.getLogger(GloablExceptionHandler.class);

    /***
     * 可能出现的未知异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public CommonResult handle(Exception e) {
        log.error(&quot;【系统异常】{}&quot;, e);
        return CommonResult.failure();
    }

    /***
     * 参数异常 -- ConstraintViolationException()
     * 用于处理类似http://localhost:8080/user/getUser?age=30&amp;name=yoyo请求中age和name的校验引发的异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = {ConstraintViolationException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public CommonResult urlParametersExceptionHandle(ConstraintViolationException e) {
        log.error(&quot;【请求参数异常】:{}&quot;, e);
        //收集所有错误信息
        List&lt;String&gt; errorMsg = e.getConstraintViolations()
                .stream().map(s -&gt; s.getMessage()).collect(Collectors.toList());
        return CommonResult.error(ResultEnum.PARAM_ERROR.getCode(), errorMsg.toString());
    }

    /***
     * 参数异常 --- MethodArgumentNotValidException和BindException
     * MethodArgumentNotValidException --- 用于处理请求参数为实体类时校验引发的异常 --- Content-Type为application/json
     * BindException --- 用于处理请求参数为实体类时校验引发的异常  --- Content-Type为application/x-www-form-urlencoded
     * @param e
     * @return
     */
    @ExceptionHandler(value = {MethodArgumentNotValidException.class, BindException.class, HttpMessageNotReadableException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public CommonResult bodyExceptionHandle(Exception e) {
        log.error(&quot;【请求参数异常】:{}&quot;, e);
        BindingResult bindingResult = null;
        if (e instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
            bindingResult = ex.getBindingResult();
        } else if (e instanceof HttpMessageNotReadableException ){
            return CommonResult.error(ResultEnum.PARAM_ERROR.getCode(), &quot;body为空&quot;);
        }else {
            BindException ex = (BindException) e;
            ex.getBindingResult();
        }
        if (bindingResult != null) {
            //收集所有错误信息
            List&lt;String&gt; errorMsg = bindingResult.getFieldErrors().stream()
                    .map(s -&gt; s.getDefaultMessage()).collect(Collectors.toList());
            return CommonResult.error(ResultEnum.PARAM_ERROR.getCode(), errorMsg.toString());
        }

        return CommonResult.error(ResultEnum.PARAM_ERROR.getCode());
    }
    /***
     * 自定义异常 --- 自定义异常一般不要设置为ERROR级别,因为我们用自定义的异常主要是为了辅助我们处理业务逻辑,
     *          --- 它们其实并不能被真正当作异常来看待
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.IM_USED)
    @ExceptionHandler(value = CommonException.class)
    public CommonResult commonExceptionHandle(CommonException e) {
        log.warn(&quot;【自定义异常】&quot;, e);
        return CommonResult.error(e.getCode(), e.getMessage());
    }
}</code></pre>
<p>分别定义url 参数异常，body 参数异常，和自定义参数异常</p>
<h2 id="统一返回处理"><a href="#统一返回处理" class="headerlink" title="统一返回处理"></a>统一返回处理</h2><pre><code class="java">package com.zhenglide.common;

public class CommonResult&lt;T&gt; {
   T data;
   Integer code;
   String message;

   /**
    * 成功返回结果
    *
    * @param data 获取的数据
    */
   public static &lt;T&gt; CommonResult&lt;T&gt; success(T data) {
      return new CommonResult&lt;T&gt;(data,ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMessage());
   }

   /**
    *
    * 失败返回结果
    * @return
    */
   public static &lt;T&gt; CommonResult&lt;T&gt; failure() {
      return new CommonResult&lt;T&gt;(ResultEnum.FAILURE.getCode(), ResultEnum.FAILURE.getMessage());
   }

   /**
    *
    * 失败返回结果
    * @return
    */
   public static &lt;T&gt; CommonResult&lt;T&gt; error(Integer code, String message) {
      return new CommonResult&lt;T&gt;(code, message);
   }
   /**
    *
    * 失败返回结果
    * @return
    */
   public static &lt;T&gt; CommonResult&lt;T&gt; error(Integer code) {
      return new CommonResult&lt;T&gt;(code);
   }
   public T getData() {
      return data;
   }

   public void setData(T data) {
      this.data = data;
   }

   public Integer getCode() {
      return code;
   }

   public void setCode(Integer code) {
      this.code = code;
   }

   public String getMessage() {
      return message;
   }

   public void setMessage(String message) {
      this.message = message;
   }

   public CommonResult(T data, Integer code, String message) {
      this.data = data;
      this.code = code;
      this.message = message;
   }
   public CommonResult( Integer code, String message) {
      this.code = code;
      this.message = message;
   }
   public CommonResult( Integer code) {
      this.code = code;
      this.message = message;
   }
}
</code></pre>
<pre><code class="java">package com.zhenglide.common;

public enum ResultEnum {
    SUCCESS(200,&quot;操作成功&quot;),
    FAILURE(500,&quot;未知异常&quot;),
    UNAUTHITHIOR(403,&quot;没有权限&quot;),
    SQLERROR(501,&quot;数据库执行异常&quot;),
    PARAM_ERROR(502,&quot;&quot;);
    int code;
    String message;

    ResultEnum(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
</code></pre>
<h2 id="body添加校验"><a href="#body添加校验" class="headerlink" title="body添加校验"></a>body添加校验</h2><pre><code class="java">@Data
public class UserDto implements Serializable {


    @NotEmpty(message = &quot;邮箱不为空&quot;)
    @Email(message = &quot;邮箱格式不正确&quot;)
    String email;
}</code></pre>
<p>需要添加 @Vaild 在方法中</p>
<img src="/homepage/2020/03/30/springboot%E5%85%A8%E5%B1%80%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E5%92%8C%E5%85%A5%E5%8F%82%E6%A0%BC%E5%BC%8F%E6%A0%A1%E9%AA%8C/body%E6%B5%8B%E8%AF%95.png" class="">

<h2 id="params添加校验"><a href="#params添加校验" class="headerlink" title="params添加校验"></a>params添加校验</h2><pre><code class="java">@RestController
@RequestMapping(&quot;user&quot;)
@Validated
public class UserController {

     @RequestMapping(&quot;getById&quot;)
    public CommonResult getById(@NotEmpty(message=&quot;id 不为空&quot;) String id){
           return  CommonResult.success(id);
     }


     @RequestMapping(&quot;add&quot;)
     public CommonResult add(@Valid @RequestBody UserDto userDto){
         return  CommonResult.success(userDto);
     }
}</code></pre>
<img src="/homepage/2020/03/30/springboot%E5%85%A8%E5%B1%80%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E5%92%8C%E5%85%A5%E5%8F%82%E6%A0%BC%E5%BC%8F%E6%A0%A1%E9%AA%8C/url%E6%A0%A1%E9%AA%8C%E6%B5%8B%E8%AF%95.png" class="">

<h2 id="添加自定义异常类"><a href="#添加自定义异常类" class="headerlink" title="添加自定义异常类"></a>添加自定义异常类</h2><h3 id="添加注解类"><a href="#添加注解类" class="headerlink" title="添加注解类"></a>添加注解类</h3><pre><code class="java">@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Constraint(validatedBy = FormatDateVaildator.class)
public @interface FormatDate {
    String formatDate() default &quot;yyyy-MM-dd HH:mm:ss&quot;;

    String message() default &quot;时期格式不正确&quot;;

    Class&lt;?&gt;[] groups() default {};

    Class&lt;? extends Payload&gt;[] payload() default {};

}</code></pre>
<h3 id="添加异常校验类"><a href="#添加异常校验类" class="headerlink" title="添加异常校验类"></a>添加异常校验类</h3><pre><code class="java">public class FormatDateVaildator implements ConstraintValidator&lt;FormatDate,String&gt; {

    private String formatDate;
    @Override
    public void initialize(FormatDate constraintAnnotation) {
        this.formatDate = constraintAnnotation.formatDate();
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {

        try {
            Date date = new SimpleDateFormat(formatDate).parse(value);
        } catch (ParseException e) {
            return false;
        }
        return true;
    }
}</code></pre>
<p>使用方式跟上面一样</p>

        
    </section>
</article>



<a id="pagenext" href="/homepage/2020/03/30/%E8%A7%A3%E5%86%B3idea%E6%97%A0%E6%B3%95%E8%AE%BF%E9%97%AE%E7%BD%91%E9%A1%B5%E9%97%AE%E9%A2%98/" class="article-next" title="解决idea无法访问网页问题"><i class="icon-arrow-right"></i></a>


<a id="pageprev" href="/homepage/2020/03/31/%E9%85%8D%E7%BD%AE%E4%B8%80%E4%B8%AA%E5%9F%9F%E5%90%8D%E5%A4%9A%E4%B8%AAvue%E9%A1%B9%E7%9B%AE%E8%AE%BF%E9%97%AE/" class="article-prev" title="配置一个域名多个vue项目访问"><i class="icon-arrow-left"></i></a>




            </div>
        </div>
        <footer class="footer">
    Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>, Theme by <a href="https://github.com/sanonz/hexo-theme-concise" target="_blank">Concise</a>

    
    <script>
        var _hmt = _hmt || [];
        (function () {
            var hm = document.createElement("script");
            hm.src = "https://hm.baidu.com/hm.js?b13bb4c2ef8300062aab9732bd22eae0";
            var s = document.getElementsByTagName("script")[0];
            s.parentNode.insertBefore(hm, s);
        })();
    </script>
    
</footer>

    </main>

    <script type="text/javascript" src="https://cdn.bootcss.com/jquery/1.9.0/jquery.min.js"></script>
    <script type="text/javascript">
    $(function() {
        var nodes = {
            nav: $('#nav'),
            aside: $('#aside'),
            asideInner: $('#aside-inner'),
            navInner: $('#nav-inner')
        };

        var doing = false;
        nodes.asideInner.on('webkitAnimationEnd mozAnimationEnd oAnimationEnd oanimationend animationend', function() {
            if (nodes.aside.hasClass('mobile-open')) {
                nodes.aside.removeClass('mobile-open');
            } else {
                nodes.aside.removeClass('mobile-close panel-show');
            }
            doing = false;
        });
        $('#open-panel, #aside-mask').on('click', function() {
            if (doing) {
                return;
            }

            if (nodes.aside.hasClass('panel-show')) {
                nodes.aside.addClass('mobile-close');
            } else {
                nodes.aside.addClass('mobile-open panel-show');
            }
        });
        $('#open-menus').on('click', function() {
            nodes.navInner.slideToggle();
        });

        if (window.innerWidth <= 960) {
            setTimeout(function() {
                nodes.navInner.slideUp();
            }, 3000);
        }
    });
    </script>
    
        
<script src="/homepage/js/scrollspy.min.js"></script>

        <script type="text/javascript">
        $(document.body).scrollspy({target: '#aside-inner'});

        $(window).on('resize', function() {
            var hw = $('#header').width();
            var ww = $('#wrapper').width();
            var space = ($(this).width() - hw - ww) / 2 / 2;

            var pageprev = $('#pageprev');
            var pagenext = $('#pagenext');
            var avg = (pageprev.width() + pagenext.width()) / 2

            if(space > avg) {
                var len = space - avg / 2;
                var styles = {position: 'fixed', top: '50%', marginTop: - (pageprev.width() + pagenext.width()) / 4}
                pageprev.css($.extend({left: hw + len}, styles));
                pagenext.css($.extend({right: len}, styles));
            } else {
                pageprev.removeAttr('style');
                pagenext.removeAttr('style');
            }
        }).trigger('resize');
        </script>
    

</body>
</html>
